package tools

import (
	"strconv"
	"strings"
)

//slice helper
//provide slice op

//SliceU64Find return first index if find slice[index] == target,
// if not found, return len(slice)
func SliceU64Find(slice []uint64, target uint64) int {
	idx := 0
	for ; idx < len(slice); idx++ {
		if slice[idx] == target {
			return idx
		}
	}
	return idx
}

//SliceU64Contains return if target in slice
func SliceU64Contains(slice []uint64, target uint64) bool {
	return SliceU64Find(slice, target) < len(slice)
}

func SliceI32Find(slice []int32, target int32) int {
	idx := 0
	for ; idx < len(slice); idx++ {
		if slice[idx] == target {
			return idx
		}
	}
	return idx
}

func SliceI32Contains(slice []int32, target int32) bool {
	return SliceI32Find(slice, target) < len(slice)
}

func SlicesFind(slice []string, target string) int {
	idx := 0
	for ; idx < len(slice); idx++ {
		if slice[idx] == target {
			return idx
		}
	}
	return idx
}

func SlicesContains(slice []string, target string) bool {
	return SlicesFind(slice, target) < len(slice)
}

type makeSlice = func(int) interface{}
type iSlieceAssign = func(int, int64)
type uSlieceAssign = func(int, uint64)

func String2SliceF(s, sep string, prepare func(int), f func(int, string) bool) {
	if f == nil {
		return
	}
	ss := strings.Split(s, sep)
	if prepare != nil {
		prepare(len(ss))
	}
	for i, s := range ss {
		if !f(i, s) {
			break
		}
	}
	return
}

func string2SliceI64F(s, sep string, prepare func(int), f func(int, int64)) error {
	var err error
	var v int64
	vistor := func(i int, s string) bool {
		if s == "" {
			return true
		}
		v, err = strconv.ParseInt(s, 10, 64)
		if err != nil {
			return false
		}
		f(i, v)
		return true
	}
	String2SliceF(s, sep, prepare, vistor)
	return err
}

func String2SliceI64F(s, sep string, f func(int, int64)) error {
	return string2SliceI64F(s, sep, nil, f)
}

func string2SliceU64F(s, sep string, prepare func(int), f func(int, uint64)) error {
	var err error
	var v uint64
	vistor := func(i int, s string) bool {
		if s == "" {
			return true
		}
		v, err = strconv.ParseUint(s, 10, 64)
		if err != nil {
			return false
		}
		f(i, v)
		return true
	}
	String2SliceF(s, sep, prepare, vistor)
	return err
}

func String2SliceU64F(s, sep string, f func(int, uint64)) error {
	return string2SliceU64F(s, sep, nil, f)
}

func String2SliceI(s, sep string) (slice []int, err error) {
	prepare := func(n int) { slice = make([]int, 0, n) }
	visitor := func(i int, v int64) { slice = append(slice, int(v)) }
	err = string2SliceI64F(s, sep, prepare, visitor)
	return
}

func String2SliceI32(s, sep string) (slice []int32, err error) {
	prepare := func(n int) { slice = make([]int32, 0, n) }
	visitor := func(i int, v int64) { slice = append(slice, int32(v)) }
	err = string2SliceI64F(s, sep, prepare, visitor)
	return
}

func String2SliceU32(s, sep string) (slice []uint32, err error) {
	prepare := func(n int) { slice = make([]uint32, 0, n) }
	visitor := func(i int, v uint64) { slice = append(slice, uint32(v)) }
	err = string2SliceU64F(s, sep, prepare, visitor)
	return
}

func String2SliceU64(s, sep string) (slice []uint64, err error) {
	prepare := func(n int) { slice = make([]uint64, 0, n) }
	visitor := func(i int, v uint64) { slice = append(slice, (v)) }
	err = string2SliceU64F(s, sep, prepare, visitor)
	return
}
